/**
 * 
 */
package officeserver.office.network;

import java.net.Socket;
import java.net.SocketException;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.logging.Level;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import officeserver.log_error.Log;
import officeserver.main.MODULE;
import officeserver.office.Office;
import officeserver.office.request.AdminRequest;
import officeserver.office.request.AdminRequest.TYPE;
import officeserver.office.request.OfficeRequest;

/**
 * @author Chris Bayruns
 * 
 */
public class NetworkConnection implements Runnable {
    private BlockingQueue<OfficeRequest> queueOut;
    private Socket mySocket;
    /** the protocol for the client */
    private ObjectOutputStream myOut = null;
    private ObjectInputStream myIn = null;
    //private BufferedOutputStream myBufOut = null;
    private BufferedInputStream myBufIn = null;
    private Office myOffice = null;
    //private ByteArrayInputStream myInKludge = null;
    
    public NetworkConnection(Socket theClient) throws SocketException {
	queueOut = new LinkedBlockingQueue<OfficeRequest>();
	mySocket = theClient;
	mySocket.setSoTimeout(1000);
    }

    // @Override
    public void run() {
	// System.out.println("Client Running");
	OfficeRequest tempReqIn = null;
	OfficeRequest tempReqOut = null;
	boolean disconnected = false;
	DataInputStream din = null;
	int num;
	byte temp[];
	this.myOffice = new Office();
	try {
		myBufIn = new BufferedInputStream(mySocket.getInputStream());
	    myIn = new ObjectInputStream(myBufIn);
		//din = new DataInputStream(mySocket.getInputStream());
		
	    myOut = new ObjectOutputStream(mySocket.getOutputStream());
	} catch (IOException e) {
	    // TODO Auto-generated catch block
	    Log.writeToLog(MODULE.NETWORK, Level.SEVERE, "IOException");
	}

	while (!Thread.interrupted() && !mySocket.isClosed() && !disconnected) {// System.out.println("Loop");
	    if (!queueOut.isEmpty()) {
		// System.out.println("Client Has something to write");
		tempReqOut = queueOut.remove();

		try {
			myOut.writeObject(tempReqOut);
			myOut.flush();
			
		    
		} catch (IOException e) {
		    // TODO Auto-generated catch block
		    e.printStackTrace();
		    Log.writeToLog(MODULE.NETWORK, Level.SEVERE, "IOException");
		}
	    } else {
		try {
		    int aval = myBufIn.available();
		    if (aval == 1) {
			// aval = mySocket.;
		    } else if (aval > 0) {
			// System.out.println("Client reading");
			try {
				
			    tempReqIn = (OfficeRequest) myIn.readObject();
			    if (tempReqIn instanceof AdminRequest) // if we need
								   // to shut
								   // down the
								   // network
			    {
				if (((AdminRequest) tempReqIn).getType() == TYPE.CON_DISCONNECT) {
				    disconnected = true;
				}
			    }
			} catch (ClassNotFoundException e) {
			    // TODO Auto-generated catch block
			    Log.writeToLog(MODULE.NETWORK, Level.SEVERE,
				    "ClassNotFoundException");
			}

			RequestQueue.enqueue(new RequestQueueWrapper(tempReqIn,
				myOffice, this));
		    }
		} catch (IOException e) {
		    // TODO Auto-generated catch block
		    Log.writeToLog(MODULE.NETWORK, Level.SEVERE, "IOException");
		    e.printStackTrace();
		}
		Thread.yield();
	    }
	}
	this.myOffice.userLogout();
	this.myOffice = null;
	try {
		//myIn.reset();
		//myOut.reset();
		myIn.close();
		myOut.close();
	    mySocket.close();
	    // System.out.println("Socket Shut Down");
	} catch (IOException e) {
	    // TODO Auto-generated catch block
	    e.printStackTrace();
	}

	// Thread.
    }

    public void enqueOut(OfficeRequest out) {
	try {
	    queueOut.put(out);
	} catch (InterruptedException e) {
	    // TODO Auto-generated catch block
	    e.printStackTrace();
	}
    }
    
    private OfficeRequest bytesToObject( byte bytes[] ) throws IOException, ClassNotFoundException
    {
    	OfficeRequest result = null;
    	
		result = (OfficeRequest) new java.io.ObjectInputStream(new
		java.io.ByteArrayInputStream(bytes)).readObject();   

		return result;
    }
    
    private static byte[] toBytes(Object object)
    {
		java.io.ByteArrayOutputStream baos = new
		java.io.ByteArrayOutputStream();
		try{
			java.io.ObjectOutputStream oos = new
			java.io.ObjectOutputStream(baos);
			oos.writeObject(object);
		}catch(java.io.IOException ioe){
			ioe.printStackTrace();
		}
		
		return baos.toByteArray();
	} 
}
